package it.traveldream.EJB;

import it.traveldream.EJB.DTO.AcquistoDTO;
import it.traveldream.EJB.DTO.CategoriaDTO;
import it.traveldream.EJB.DTO.DisponibilitaDTO;
import it.traveldream.EJB.DTO.EscursioneDTO;
import it.traveldream.EJB.DTO.GiftListDTO;
import it.traveldream.EJB.DTO.PacchettoDTO;
import it.traveldream.EJB.DTO.TrasportoSingoloDTO;
import it.traveldream.EJB.DTO.UtenteDTO;
import it.traveldream.EJB.entities.Acquisti;
import it.traveldream.EJB.entities.AcquistiPK;
import it.traveldream.EJB.entities.Categorie;
import it.traveldream.EJB.entities.Disponibilita;
import it.traveldream.EJB.entities.Escursioni;
import it.traveldream.EJB.entities.GiftList;
import it.traveldream.EJB.entities.Pacchetti;
import it.traveldream.EJB.entities.TrasportiSingoli;
import it.traveldream.EJB.entities.User;
import it.traveldream.utility.DTO2Entities;
import it.traveldream.utility.Entities2DTO;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import com.sun.corba.se.spi.servicecontext.UEInfoServiceContext;
import com.sun.xml.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;

/**
 * Session Bean implementation class PacketBeanImpl
 */
@Stateless
public class PacketBeanImpl implements PacketBeanEJB {

	public PacketBeanImpl() {}

	@PersistenceContext
	EntityManager em;

	/**
	 * Ritorna la lista di pacchetti che un impiegato pu� vedere
	 * 
	 * @return l'{@link ArrayList} dei PacchettiDTO
	 * 
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public ArrayList<PacchettoDTO> getPacketList() {

		List<Pacchetti> res = em.createQuery("SELECT p FROM Pacchetti p WHERE p.deleted = 0").getResultList();
		Iterator<Pacchetti> iter = res.iterator();

		UtenteEJBImpl uejb = new UtenteEJBImpl(em);

		ArrayList<PacchettoDTO> result = new ArrayList<PacchettoDTO>();

		while(iter.hasNext()){
			result.add(Entities2DTO.convertPacchetti(iter.next(),uejb.getAllUtenti()));
		}

		return result;

	}

	/**
	 * Ritorna la lista di pacchetti che un cliente pu� vedere
	 * 
	 * @param userid = la stringa contenente l'id del cliente
	 * 
	 * @return l'{@link ArrayList} dei PacchettiDTO
	 * 
	 */
	@Override
	@RolesAllowed({"USERS"})
	public ArrayList<PacchettoDTO> getPacketListCliente(String username) {

		UtenteEJBImpl uejb = new UtenteEJBImpl(em);

		List<User> lu;
		int uid;
		Iterator<User> internator;
		UtenteDTO pr = new UtenteDTO();

		ArrayList<PacchettoDTO> ret=new ArrayList<PacchettoDTO>();
		List<Pacchetti> entita;

		lu = em.createQuery("SELECT u FROM User u WHERE u.userid= :uid").setParameter("uid", username).getResultList();
		internator = lu.iterator();

		uid = internator.next().getIdUtente();
		entita=em.createQuery("SELECT p FROM Pacchetti p WHERE p.deleted = 0 AND (p.custom = 0 OR p.customDa= :userid) AND p.disponibilita>0").setParameter("userid", uid).getResultList();

		Iterator<Pacchetti> i = entita.iterator();

		while(i.hasNext()){
			ret.add(Entities2DTO.convertPacchetti(i.next(),uejb.getAllUtenti()));
		}

		return ret;
	}

	/**
	 * Inserisce un nuovo pacchetto nel DB
	 * 
	 * @param newp = il {@link PacchettoDTO} da inserire
	 * 
	 */
	@Override
	public void insertNewPacket(PacchettoDTO newp) throws Exception{

		UtenteEJBImpl uejb = new UtenteEJBImpl(em);

		ArrayList<EscursioneDTO> esc = newp.getEscursionis();

		Iterator<EscursioneDTO> iterator = esc.iterator();

		List<Escursioni> l = new ArrayList<Escursioni>();
		while(iterator.hasNext()){
			l.add(DTO2Entities.convertEscursioneDTO(iterator.next()));
		}


		SBEJBBeanImpl beanservizi = new SBEJBBeanImpl(em);
		// RECUPERO LE DISPONIBILITA PER L'ALLOGGIO SCELTO NEL PACCHETTO PER POI AGGIORNARLE
		ArrayList<DisponibilitaDTO> arraydisp = beanservizi.getDisponibilitaForAlloggio(newp.getAlloggi());
		Iterator<DisponibilitaDTO> it = arraydisp.iterator();

		Disponibilita temp = new Disponibilita();
		DisponibilitaDTO scorri = new DisponibilitaDTO();

		TrasportoSingoloDTO tempand = newp.getTrasportAndata();
		TrasportoSingoloDTO temprit = newp.getTrasportRitorno();

		// SETTO L'ID DELL'IMPIEGATO PARTENDO DAL SUO USERNAME
		newp.getCreato_da().setIduser(uejb.getIdFromUsername(newp.getCreato_da().getUsername()));

		Pacchetti entity = new Pacchetti();
		entity = DTO2Entities.convertPacchettoDTO(newp);

		// AGGIORNO LE DISPONIBILITA DEGLI ALLOGGI
		while(it.hasNext()){
			scorri=it.next();
			// CONTROLLO QUALI SONO LE DISPONIBILITA DA AGGIORNARE
			if(scorri.getTipoCamera().equalsIgnoreCase(newp.getTipocamera())){
				if(scorri.getData().compareTo(tempand.getData())==0||scorri.getData().compareTo(temprit.getData())==0||(scorri.getData().compareTo(temprit.getData())<0&&scorri.getData().compareTo(tempand.getData())>0)){
					scorri.setNumerocamere(scorri.getNumerocamere()-entity.getDisponibilita());
					temp=DTO2Entities.convertDisponibilitaDTO(scorri);
					try{
						beanservizi.updateDisponibilita(temp);
					}catch(Exception e){
						throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
					}
				}
			}
		}

		// AGGIORNO I TRASPORTI		
		tempand.setDisponibilita(tempand.getDisponibilita()-entity.getDisponibilita()*entity.getTipocamera());
		temprit.setDisponibilita(temprit.getDisponibilita()-entity.getDisponibilita()*entity.getTipocamera());

		try{
			int row=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ tempand.getDisponibilita() + " WHERE t.idTrasporto = " + tempand.getIdTrasporto()).executeUpdate();
			int rowl=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ temprit.getDisponibilita() + " WHERE t.idTrasporto = " + temprit.getIdTrasporto()).executeUpdate();
			if(row!=1||rowl!=1){
				throw new Exception("AGGIORNATI "+row+" e "+rowl+" TRASPORTI ZIO PORCONE");
			}
		}catch(Exception e){
			throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA TRASPORTI PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
		}

		// INSERISCO UN PACCHETTO NEL DB

		Iterator<Escursioni> i1 = l.iterator();
		while(i1.hasNext()){
			entity.addEscursione(i1.next());
		}
		try{

			//em.persist(entity);
			em.createNativeQuery("INSERT INTO PACCHETTI ( sconto, custom, categoria, custom_da, trasporto_andata, trasporto_ritorno, creato_da, alloggio, deleted, disponibilita, tipocamera ) VALUES( " + entity.getSconto() +" , " + entity.getCustom() +" , " + entity.getCategorie().getIdCategoria()
					+ " , " + ((entity.getCustomDa() == 0) ? "NULL" : entity.getCustomDa())+" , " + entity.getTrasportiSingoli1().getIdTrasporto() +" , " + entity.getTrasportiSingoli2().getIdTrasporto()+ " , " +
					entity.getCreatoDa() +" , " +  entity.getAlloggi().getIdAlloggio() +" , " +entity.getDeleted() +" , " + entity.getDisponibilita() + " , " + entity.getTipocamera() +
					") " ).executeUpdate();
			

			List<Pacchetti> p =  em.createQuery("SELECT p FROM Pacchetti p ORDER BY p.idPacchetto DESC").getResultList();



			i1 = l.iterator();
			Escursioni help;
			while(i1.hasNext()){
				help = i1.next();
				em.createNativeQuery("INSERT INTO ESCURSIONI_X_PACCHETTI (id_pacchetto, id_escursione) VALUES ( " + p.get(0).getIdPacchetto() + " , " + help.getIdEscursione() + ")" ).executeUpdate();
			}

		}catch(Exception e){
			throw new Exception("ERRORE INSERIMENTO NUOVO PACCHETTO: "+e.getMessage());
		}

	}
	
	
	
	/**
	 * Inserisce un nuovo pacchetto customizzato nel DB
	 * 
	 * @param newp = il {@link PacchettoDTO} da inserire
	 * 
	 */
	@Override
	public void insertNewPacketCustom(PacchettoDTO newp) throws Exception{

		UtenteEJBImpl uejb = new UtenteEJBImpl(em);

		ArrayList<EscursioneDTO> esc = newp.getEscursionis();

		Iterator<EscursioneDTO> iterator = esc.iterator();

		List<Escursioni> l = new ArrayList<Escursioni>();
		while(iterator.hasNext()){
			l.add(DTO2Entities.convertEscursioneDTO(iterator.next()));
		}


		SBEJBBeanImpl beanservizi = new SBEJBBeanImpl(em);
		// RECUPERO LE DISPONIBILITA PER L'ALLOGGIO SCELTO NEL PACCHETTO PER POI AGGIORNARLE
		ArrayList<DisponibilitaDTO> arraydisp = beanservizi.getDisponibilitaForAlloggio(newp.getAlloggi());
		Iterator<DisponibilitaDTO> it = arraydisp.iterator();

		Disponibilita temp = new Disponibilita();
		DisponibilitaDTO scorri = new DisponibilitaDTO();

		TrasportoSingoloDTO tempand = newp.getTrasportAndata();
		TrasportoSingoloDTO temprit = newp.getTrasportRitorno();

		// SETTO L'ID DELL'IMPIEGATO PARTENDO DAL SUO USERNAME
		newp.getCreato_da().setIduser(uejb.getIdFromUsername(newp.getCreato_da().getUsername()));

		Pacchetti entity = new Pacchetti();
		entity = DTO2Entities.convertPacchettoDTO(newp);

		// AGGIORNO LE DISPONIBILITA DEGLI ALLOGGI
		while(it.hasNext()){
			scorri=it.next();
			// CONTROLLO QUALI SONO LE DISPONIBILITA DA AGGIORNARE
			if(scorri.getTipoCamera().equalsIgnoreCase(newp.getTipocamera())){
				if(scorri.getData().compareTo(tempand.getData())==0||scorri.getData().compareTo(temprit.getData())==0||(scorri.getData().compareTo(temprit.getData())<0&&scorri.getData().compareTo(tempand.getData())>0)){
					scorri.setNumerocamere(scorri.getNumerocamere()-entity.getDisponibilita());
					temp=DTO2Entities.convertDisponibilitaDTO(scorri);
					try{
						beanservizi.updateDisponibilita(temp);
					}catch(Exception e){
						throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
					}
				}
			}
		}

		// AGGIORNO I TRASPORTI		
		tempand.setDisponibilita(tempand.getDisponibilita()-entity.getDisponibilita()*entity.getTipocamera());
		temprit.setDisponibilita(temprit.getDisponibilita()-entity.getDisponibilita()*entity.getTipocamera());

		try{
			int row=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ tempand.getDisponibilita() + " WHERE t.idTrasporto = " + tempand.getIdTrasporto()).executeUpdate();
			int rowl=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ temprit.getDisponibilita() + " WHERE t.idTrasporto = " + temprit.getIdTrasporto()).executeUpdate();
			if(row!=1||rowl!=1){
				throw new Exception("AGGIORNATI "+row+" e "+rowl+" TRASPORTI ZIO PORCONE");
			}
		}catch(Exception e){
			throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA TRASPORTI PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
		}

		// INSERISCO UN PACCHETTO NEL DB

		Iterator<Escursioni> i1 = l.iterator();
		while(i1.hasNext()){
			entity.addEscursione(i1.next());
		}
		try{

			//em.persist(entity);
			em.createNativeQuery("INSERT INTO PACCHETTI ( sconto, custom, categoria, custom_da, trasporto_andata, trasporto_ritorno, creato_da, alloggio, deleted, disponibilita, tipocamera ) VALUES( " + entity.getSconto() +" , " + entity.getCustom() +" , " + entity.getCategorie().getIdCategoria()
					+ " , " + ((entity.getCustomDa() == 0) ? "NULL" : entity.getCustomDa())+" , " + entity.getTrasportiSingoli1().getIdTrasporto() +" , " + entity.getTrasportiSingoli2().getIdTrasporto()+ " , " +
					entity.getCreatoDa() +" , " +  entity.getAlloggi().getIdAlloggio() +" , " +entity.getDeleted() +" , " + entity.getDisponibilita() + " , " + entity.getTipocamera() +
					") " ).executeUpdate();
			
			
			
			
			List<Pacchetti> p =  em.createQuery("SELECT p FROM Pacchetti p ORDER BY p.idPacchetto DESC").getResultList();
			
			
			
			//recupero l'id del pacchetto appena inserito
			
			
			newp.setIdPacchetto(p.iterator().next().getIdPacchetto());
			
			
			
			i1 = l.iterator();
			Escursioni help;
			while(i1.hasNext()){
				help = i1.next();
				em.createNativeQuery("INSERT INTO ESCURSIONI_X_PACCHETTI (id_pacchetto, id_escursione) VALUES ( " + p.get(0).getIdPacchetto() + " , " + help.getIdEscursione() + ")" ).executeUpdate();
			}

		}catch(Exception e){
			throw new Exception("ERRORE INSERIMENTO NUOVO PACCHETTO: "+e.getMessage());
		}

	}
	
	
	
	/**
	 * Aggiorna il campo deleted di un pacchetto nel database a 1, cancellandolo dal DB lato applicazione
	 * 
	 * @param p = il {@link PacchettoDTO} ricevuto con le nuove informazioni
	 * 
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public void deletePacchetto(PacchettoDTO p) throws Exception{

		SBEJBBeanImpl beanservizi = new SBEJBBeanImpl(em);

		Pacchetti toDelete = new Pacchetti();

		toDelete = DTO2Entities.convertPacchettoDTO(p);

		// CONTROLLO IL PACCHETTO
		if(!verificaPacchettoModificabile(toDelete)){
			throw new Exception("CANCELLAZIONE NON AVVENUTA: PACCHETTO GIA INSERITO IN GIFT LIST OPPURE GIA ACQUISTATO");
		}

		// QUI IL PACCHETTO VIENE CANCELLATO ==> VUOL DIRE CHE NESSUNO LO AVEVA ANCORA ACQUISTATO O MESSO IN GIFT LIST
		try{
			int rows=em.createQuery("UPDATE Pacchetti p SET p.deleted = 1 WHERE p.idPacchetto="+toDelete.getIdPacchetto()).executeUpdate();
			if(rows!=1){
				throw new Exception("LA QUERY HA AGGIORNATO "+rows+" TUPLE INVECE CHE 1");
			}
		}catch(Exception e){
			throw new Exception("ERRORE CANCELLAZIONE PACCHETTO: " + e.getMessage());
		}

		// INIZIO SEZIONE AGGIORNAMENTO DISPONIBILITA
		TrasportoSingoloDTO tempand = p.getTrasportAndata();
		TrasportoSingoloDTO temprit = p.getTrasportRitorno();
		Disponibilita temp = new Disponibilita();
		DisponibilitaDTO scorri = new DisponibilitaDTO();
		ArrayList<DisponibilitaDTO> arraydisp = beanservizi.getDisponibilitaForAlloggio(p.getAlloggi());
		Iterator<DisponibilitaDTO> it = arraydisp.iterator();

		// AGGIORNO LE DISPONIBILITA DEGLI ALLOGGI
		while(it.hasNext()){
			scorri=it.next();
			// CONTROLLO QUALI SONO LE DISPONIBILITA DA AGGIORNARE
			if(scorri.getTipoCamera().equalsIgnoreCase(p.getTipocamera())){
				if(scorri.getData().compareTo(tempand.getData())==0||scorri.getData().compareTo(temprit.getData())==0||(scorri.getData().compareTo(temprit.getData())<0&&scorri.getData().compareTo(tempand.getData())>0)){
					scorri.setNumerocamere(scorri.getNumerocamere()+toDelete.getDisponibilita());
					temp=DTO2Entities.convertDisponibilitaDTO(scorri);
					try{
						beanservizi.updateDisponibilita(temp);
					}catch(Exception e){
						throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA DOPO CANCELLAZIONE PACCHETTO: "+e.getMessage());
					}
				}
			}
		}

		// AGGIORNO DISPONIBILITA TRASPORTI
		tempand.setDisponibilita(tempand.getDisponibilita()+toDelete.getDisponibilita()*toDelete.getTipocamera());
		temprit.setDisponibilita(temprit.getDisponibilita()+toDelete.getDisponibilita()*toDelete.getTipocamera());

		try{
			int row=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ tempand.getDisponibilita() + " WHERE t.idTrasporto = " + tempand.getIdTrasporto()).executeUpdate();
			int rowl=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ temprit.getDisponibilita() + " WHERE t.idTrasporto = " + temprit.getIdTrasporto()).executeUpdate();
			if(row!=1||rowl!=1){
				throw new Exception("AGGIORNATI "+row+" e "+rowl+" TRASPORTI ZIO PORCONE");
			}
		}catch(Exception e){
			throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA TRASPORTI DOPO CANCELLAZIONE PACCHETTO: "+e.getMessage());
		}

		// TOLGO DA ESCURSIONI_X_PACCHETTI
		try{
			int rowes=em.createNativeQuery("DELETE FROM ESCURSIONI_X_PACCHETTI WHERE id_pacchetto="+toDelete.getIdPacchetto()).executeUpdate();
			if(rowes<=0){
				throw new Exception("NON HO CANCELLATO NESSUNA TUPLA IN ESCURSIONI_X_PACCHETTI ZIO CANE");
			}
		}catch(Exception e){
			throw new Exception("ERRORE CANCELLAZIONE DA ESCURSIONI_X_PACCHETTI: "+e.getMessage());
		}

	}

	/**
	 * Aggiorna le informazioni di un pacchetto nel database
	 * 
	 * @param p = il {@link PacchettoDTO} ricevuto con le nuove informazioni
	 * 
	 * @return p se la query � andata a buon fine p viene semplicemente riaggiornato con gli stessi valori che aveva all'inizio del metodo
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public PacchettoDTO updatePacchetto(PacchettoDTO p) throws Exception{

		SBEJBBeanImpl beanservizi = new SBEJBBeanImpl(em);
		UtenteEJBImpl uejb = new UtenteEJBImpl(em);

		Pacchetti updated = new Pacchetti();

		updated = DTO2Entities.convertPacchettoDTO(p);

		// INIZIO SEZIONE AGGIORNAMENTO DISPONIBILITA ALLOGGI E TRASPORTI
		PacchettoDTO oldpck = getPacketById(p);
		TrasportoSingoloDTO oldtempand = oldpck.getTrasportAndata();
		TrasportoSingoloDTO oldtemprit = oldpck.getTrasportRitorno();
		TrasportoSingoloDTO newtempand = p.getTrasportAndata();
		TrasportoSingoloDTO newtemprit = p.getTrasportRitorno();
		Disponibilita temp = new Disponibilita();
		DisponibilitaDTO scorri = new DisponibilitaDTO();
		ArrayList<DisponibilitaDTO> oldarraydisp = beanservizi.getDisponibilitaForAlloggio(oldpck.getAlloggi());
		ArrayList<DisponibilitaDTO> newarraydisp = beanservizi.getDisponibilitaForAlloggio(p.getAlloggi());
		Iterator<DisponibilitaDTO> oldit = oldarraydisp.iterator();
		Iterator<DisponibilitaDTO> newit = newarraydisp.iterator();
		EscursioneDTO tempesc = new EscursioneDTO();
		ArrayList<EscursioneDTO> oldescur = oldpck.getEscursionis();
		ArrayList<EscursioneDTO> newescur = p.getEscursionis();
		Iterator<EscursioneDTO> oldesc = oldescur.iterator();
		Iterator<EscursioneDTO> newesc = newescur.iterator();

		// SE I TRASPORTI SONO CAMBIATI LI AGGIORNO
		if(oldtempand.getIdTrasporto()!=newtempand.getIdTrasporto()){
			newtempand.setDisponibilita(newtempand.getDisponibilita()-updated.getDisponibilita()*updated.getTipocamera());
			oldtempand.setDisponibilita(oldtempand.getDisponibilita()+oldpck.getDisponibilita()*updated.getTipocamera());
			try{
				int row=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ newtempand.getDisponibilita() + " WHERE t.idTrasporto = " + newtempand.getIdTrasporto()).executeUpdate();
				int rowl=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ oldtempand.getDisponibilita() + " WHERE t.idTrasporto = " + oldtempand.getIdTrasporto()).executeUpdate();
				if(row!=1||rowl!=1){
					throw new Exception("AGGIORNATI "+row+" e "+rowl+" TRASPORTI ZIO PORCONE");
				}
			}catch(Exception e){
				throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA TRASPORTI PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
			}
		}
		if(oldtemprit.getIdTrasporto()!=newtemprit.getIdTrasporto()){
			newtemprit.setDisponibilita(newtemprit.getDisponibilita()-updated.getDisponibilita()*updated.getTipocamera());
			oldtemprit.setDisponibilita(oldtemprit.getDisponibilita()+oldpck.getDisponibilita()*updated.getTipocamera());
			try{
				int row=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ newtemprit.getDisponibilita() + " WHERE t.idTrasporto = " + newtemprit.getIdTrasporto()).executeUpdate();
				int rowl=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ oldtemprit.getDisponibilita() + " WHERE t.idTrasporto = " + oldtemprit.getIdTrasporto()).executeUpdate();
				if(row!=1||rowl!=1){
					throw new Exception("AGGIORNATI "+row+" e "+rowl+" TRASPORTI ZIO PORCONE");
				}
			}catch(Exception e){
				throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA TRASPORTI PRIMA DI UPDATE PACCHETTO: "+e.getMessage());
			}
		}

		// SE I TRASPORTI SONO RIMASTI UGUALI MA L'IMPIEGATO HA CAMBIATO IL NUMERO DI PACCHETTI ACQUISTABILI
		if(oldtempand.getIdTrasporto()==newtempand.getIdTrasporto()&&oldtemprit.getIdTrasporto()==newtemprit.getIdTrasporto()&&oldpck.getDisponibilita()!=p.getDisponibilita()){

			newtemprit.setDisponibilita(newtemprit.getDisponibilita()+(oldpck.getDisponibilita()-updated.getDisponibilita())*updated.getTipocamera());
			newtempand.setDisponibilita(newtempand.getDisponibilita()+(oldpck.getDisponibilita()-updated.getDisponibilita())*updated.getTipocamera());
			try{
				int row=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ newtemprit.getDisponibilita() + " WHERE t.idTrasporto = " + newtemprit.getIdTrasporto()).executeUpdate();
				int rowl=em.createQuery("UPDATE TrasportiSingoli t SET t.disponibilita = "+ newtempand.getDisponibilita() + " WHERE t.idTrasporto = " + newtempand.getIdTrasporto()).executeUpdate();
				if(row!=1||rowl!=1){
					throw new Exception("AGGIORNATI "+row+" e "+rowl+" TRASPORTI ZIO PORCONE");
				}
			}catch(Exception e){
				throw new Exception("PORCO DIAZ ERRORE UPDATE DISPONIBILITA TRASPORTO"+e.getMessage());
			}

		}

		// SE E' CAMBIATO L'ALLOGGIO
		if(p.getAlloggi().getIdAlloggio()!=oldpck.getAlloggi().getIdAlloggio()){
			// TOLGO LE DISPONIBILITA NEL NUOVO ALLOGGIO
			while(newit.hasNext()){
				scorri=newit.next();
				// CONTROLLO QUALI SONO LE DISPONIBILITA DA AGGIORNARE
				if(scorri.getTipoCamera().equalsIgnoreCase(p.getTipocamera())){
					if(scorri.getData().compareTo(newtempand.getData())==0||scorri.getData().compareTo(newtemprit.getData())==0||(scorri.getData().compareTo(newtemprit.getData())<0&&scorri.getData().compareTo(newtempand.getData())>0)){
						scorri.setNumerocamere(scorri.getNumerocamere()-updated.getDisponibilita());
						temp=DTO2Entities.convertDisponibilitaDTO(scorri);
						try{
							beanservizi.updateDisponibilita(temp);
						}catch(Exception e){
							throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
						}
					}
				}
			}
			// RIAGGIUNGO LE DISPONIBILITA AL VECCHIO
			while(oldit.hasNext()){
				scorri=oldit.next();
				// CONTROLLO QUALI SONO LE DISPONIBILITA DA AGGIORNARE
				if(scorri.getTipoCamera().equalsIgnoreCase(p.getTipocamera())){
					if(scorri.getData().compareTo(newtempand.getData())==0||scorri.getData().compareTo(newtemprit.getData())==0||(scorri.getData().compareTo(newtemprit.getData())<0&&scorri.getData().compareTo(newtempand.getData())>0)){
						scorri.setNumerocamere(scorri.getNumerocamere()+oldpck.getDisponibilita());
						temp=DTO2Entities.convertDisponibilitaDTO(scorri);
						try{
							beanservizi.updateDisponibilita(temp);
						}catch(Exception e){
							throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
						}
					}
				}
			}
		}

		// SE E' CAMBIATO IL NUMERO DI PACCHETTI MA GLI ALLOGGI SONO RIMASTI UGUALI
		if(p.getAlloggi().getIdAlloggio()!=oldpck.getAlloggi().getIdAlloggio()&&oldpck.getDisponibilita()!=p.getDisponibilita()){
			while(newit.hasNext()){
				scorri=newit.next();
				// CONTROLLO QUALI SONO LE DISPONIBILITA DA AGGIORNARE
				if(scorri.getTipoCamera().equalsIgnoreCase(p.getTipocamera())){
					if(scorri.getData().compareTo(newtempand.getData())==0||scorri.getData().compareTo(newtemprit.getData())==0||(scorri.getData().compareTo(newtemprit.getData())<0&&scorri.getData().compareTo(newtempand.getData())>0)){
						scorri.setNumerocamere(scorri.getNumerocamere()+(oldpck.getDisponibilita()-updated.getDisponibilita()));
						temp=DTO2Entities.convertDisponibilitaDTO(scorri);
						try{
							beanservizi.updateDisponibilita(temp);
						}catch(Exception e){
							throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA PRIMA DI INSERIMENTO PACCHETTO: "+e.getMessage());
						}
					}
				}
			}
		}

		// TOLGO LE VECCHIE ESCURSIONI NELLA TABELLA MANY-TO-MANY E METTO LE NUOVE (ANCHE SE SONO UGUALI, CAZZOMENE)
		while(oldesc.hasNext()){
			tempesc=oldesc.next();
			try{
				int deleted = em.createNativeQuery("DELETE FROM ESCURSIONI_X_PACCHETTI WHERE id_pacchetto="+updated.getIdPacchetto()+" AND id_escursione="+tempesc.getIdEscursione()).executeUpdate();
				if(deleted!=1){
					throw new Exception("CANCELLATE "+deleted+" UPLE ANZICHE' UNA");
				}
			}catch(Exception e){
				throw new Exception("ERRORE AGGIORNAMENTO ESCURSIONI_X_PACCHETTI: "+e.getMessage());
			}
		}
		while(newesc.hasNext()){
			tempesc=newesc.next();
			try{
				int added = em.createNativeQuery("INSERT INTO ESCURSIONI_X_PACCHETTI (id_pacchetto,id_escursione) VALUES ("+updated.getIdPacchetto()+" , "+tempesc.getIdEscursione()+")").executeUpdate();
				if(added!=1){
					throw new Exception("CANCELLATE "+added+" UPLE ANZICHE' UNA");
				}
			}catch(Exception e){
				throw new Exception("ERRORE AGGIORNAMENTO ESCURSIONI_X_PACCHETTI: "+e.getMessage());
			}
		}

		// UPDATE PACCHETTO
		try{

			int rows = em.createQuery("UPDATE Pacchetti p SET p.sconto="+updated.getSconto()+",p.categorie= :par1 , p.trasportiSingoli1= :par2 , "+
					" p.trasportiSingoli2= :par3 , p.alloggi= :par4 , p.disponibilita="+updated.getDisponibilita()+" WHERE p.idPacchetto="+updated.getIdPacchetto())
					.setParameter("par1", updated.getCategorie()).setParameter("par2", updated.getTrasportiSingoli1()) 
					.setParameter("par3", updated.getTrasportiSingoli2()).setParameter("par4", updated.getAlloggi()).executeUpdate();

			/*
			updated=em.merge(updated);
			em.flush();*/

			if(rows!=1){
				throw new Exception("PACCHETTI AGGIORNATI "+rows+" INVECE CHE 1");
			}

		}catch(Exception e){
			throw new Exception("ERRORE AGGIORNAMENTO PACCHETTO: " + e.getMessage());
		}


		return p;

	}

	/**
	 * Aggiunge al DB tante tuple alla tabella GIFTLIST quanti sono i servizi base del pacchetto desiderato
	 * 
	 * @param pkg = il {@link PacchettoDTO} che l'utente ha selezionato per la propria GiftList
	 * @param usr = l'{@link UtenteDTO} utilizzatore del metodo
	 * 
	 */
	@Override
	@RolesAllowed({"USERS"})
	public void addPacket2GiftList(PacchettoDTO pkg,
			UtenteDTO usr) throws Exception {

		UtenteEJBImpl uejb = new UtenteEJBImpl(em);
		int iduser=0;

		ArrayList<GiftListDTO> result = new ArrayList<GiftListDTO>();

		GiftListDTO temp = new GiftListDTO();

		// RECUPERO L'ID DELL'UTENTE LOGGATO TRAMITE LO USERNAME
		iduser=uejb.getIdFromUsername(usr.getUsername());

		// DATI TRASPORTO ANDATA
		temp=new GiftListDTO();
		temp.setAcquistato(0);
		temp.setIdServizioBase(pkg.getTrasportAndata().getIdTrasporto());
		temp.setUsernameUtente(usr.getUsername());
		temp.setPacchetto(pkg);

		//tipo di servizio base
		temp.setTipo_servizio_base(1);

		result.add(temp);

		// DATI TRASPORTO RITORNO
		temp=new GiftListDTO();
		temp.setAcquistato(0);
		temp.setIdServizioBase(pkg.getTrasportRitorno().getIdTrasporto());
		temp.setUsernameUtente(usr.getUsername());
		temp.setPacchetto(pkg);
		//tipo di servizio base
		temp.setTipo_servizio_base(1);
		result.add(temp);

		//DATI ALLOGGIO
		temp=new GiftListDTO();
		temp.setAcquistato(0);
		temp.setIdServizioBase(pkg.getAlloggi().getIdAlloggio());
		temp.setUsernameUtente(usr.getUsername());
		temp.setPacchetto(pkg);
		//tipo di servizio base
		temp.setTipo_servizio_base(2);
		result.add(temp);

		// DATI ESCURSIONI
		Iterator<EscursioneDTO> iterEscur = pkg.getEscursionis().iterator();

		while(iterEscur.hasNext()){
			temp=new GiftListDTO();
			temp.setAcquistato(0);
			temp.setIdServizioBase(iterEscur.next().getIdEscursione());
			temp.setUsernameUtente(usr.getUsername());
			temp.setPacchetto(pkg);
			//tipo di servizio base
			temp.setTipo_servizio_base(3);
			result.add(temp);

		}

		// result CONTIENE LE TUPLE DA INSERIRE NEL DB NELLA TABELLA GiftList
		Iterator<GiftListDTO> i = result.iterator();
		GiftList entity = new GiftList();

		while(i.hasNext()){
			entity=DTO2Entities.convertGiftListDTO(i.next(),em);
			System.out.println("DATI:idpacchetto: "+entity.getPacchetti().getIdPacchetto()+" idservbase: "+entity.getIdServizioBase()+" tiposervbase: "+entity.getTipo_servizioBase());
			try{
				em.createNativeQuery("INSERT INTO gift_list (id_pacchetto,id_utente,id_servizio_base,acquistato,acquistato_da,tipo_servBase) VALUES "
						+ "("+entity.getPacchetti().getIdPacchetto()+","+entity.getIdUtente()+","+entity.getIdServizioBase()+",0,NULL,"
						+ entity.getTipo_servizioBase()+")").executeUpdate();
				//em.persist(entity);
			}catch(Exception e){
				throw new Exception("ERRORE INSERIMENTO ELEMENTO GIFT LIST: "+e.getMessage());
			}
		}

	}

	/**
	 * Metodo che restituisce un {@link PacchettoDTO} cercato nel DB usando il suo id
	 * 
	 * @param pck = il {@link PacchettoDTO} passato che poi sar� ritornato con le info recuperate
	 * 
	 * @return pck
	 * 
	 */
	@Override
	public PacchettoDTO getPacketById(PacchettoDTO pck){

		UtenteEJBImpl uejb = new UtenteEJBImpl(em);

		List<Pacchetti> lp;
		Iterator<Pacchetti> ip;

		lp = em.createQuery("SELECT p FROM Pacchetti p WHERE p.idPacchetto= :idp").setParameter("idp", pck.getIdPacchetto()).getResultList();
		if(!lp.isEmpty()){
			ip=lp.iterator();

			pck=Entities2DTO.convertPacchetti(ip.next(), uejb.getAllUtenti());
		}else{
			pck = null;
		}
		return pck;
	}

	/**
	 * Inserisce una nuova categoria nel DB
	 * 
	 * @param cat = il {@link CategoriaDTO}
	 * 
	 */
	@Override
	@RolesAllowed({"ADMINS"})
	public void insertNewCategoria(CategoriaDTO cat) throws Exception{
		Categorie c = new Categorie();
		c=DTO2Entities.convertCategoriaDTO(cat);

		try{
			em.persist(c);
		}catch(Exception e){
			throw new Exception("ERRORE INSERIMENTO NUOVA CATEGORIA: "+e.getMessage());
		}

	}

	/**
	 * Cerca e restituisce tutte le {@link Categorie}
	 * 
	 * @return l'{@link ArrayList} di {@link CategoriaDTO}
	 * 
	 */
	@Override
	public ArrayList<CategoriaDTO> getAllCategorie(){
		List<Categorie> lc;
		Iterator<Categorie> itc;
		ArrayList<CategoriaDTO> ret = new ArrayList<CategoriaDTO>();

		lc = em.createQuery("SELECT c FROM Categorie c").getResultList();
		itc = lc.iterator();

		while(itc.hasNext()){
			ret.add(Entities2DTO.convertCategorie(itc.next()));
		}

		return ret;
	}

	/**
	 * Controlla che un {@link Pacchetti} sia modificabile o cancellabile
	 * 
	 * @param p = il pacchetto da controllare
	 * 
	 * @return {@link true} se � non � presente in Acquisti o GiftList, {@link false} altrimenti
	 * 
	 */
	public boolean verificaPacchettoModificabile(Pacchetti p) throws Exception{
		if(!em.createQuery("SELECT g FROM GiftList g WHERE g.pacchetti= :pacc").setParameter("pacc", p).getResultList().isEmpty()){
			return false;
		}
		if(!em.createQuery("SELECT a FROM Acquisti a WHERE a.pacchetti= :pacc").setParameter("pacc", p).getResultList().isEmpty()){
			return false;
		}
		return true;
	}

	/**
	 * Inserisce un nuovo {@link Acquisti} nel DB
	 * 
	 * @param a = l'{@link AcquistoDTO} da inserire
	 * @throws Exception
	 */
	@Override
	public void acquistaPacchetto(AcquistoDTO a) throws Exception{
		UtenteEJBImpl uejb = new UtenteEJBImpl(em);
		int uid = uejb.getIdFromUsername(a.getUtente().getUsername());
		a.getUtente().setIduser(uid);
		Acquisti acq = DTO2Entities.convertAcquistoDTO(a);
		
		try{
			System.out.println(acq.getNumeroAcquisti() + ", " + acq.getId().getIdPacchetto() + "=" + acq.getPacchetti().getIdPacchetto() + "\n\n " + acq.getId().getIdUtente());
			em.persist(acq);
		}catch(Exception e){
			throw new Exception("ERRORE INSERIMENTO ACQUISTO: "+e.getMessage());
		}

		// UPDATE DISPONIBILITA PACCHETTO
		try{
			int rows = em.createQuery("UPDATE Pacchetti p SET p.disponibilita="+(acq.getPacchetti().getDisponibilita()-acq.getNumeroAcquisti())+" "
					+ "WHERE p.idPacchetto="+acq.getPacchetti().getIdPacchetto()).executeUpdate();
			if(rows!=1){
				throw new Exception("ZIO CANE, "+rows+" TUPLE INVECE CHE UNA");
			}
		}catch(Exception e){
			throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA: "+e.getMessage());
		}

	}

	/**
	 * Inserisce un nuovo {@link Acquisti} nel DB - VERSIONE NATIVE QUERY
	 * 
	 * @param a = l'{@link AcquistoDTO} da inserire
	 * @throws Exception
	 */
	public void provaAcquistiNative(AcquistoDTO a) throws Exception{
		Acquisti acq = DTO2Entities.convertAcquistoDTO(a);

		try{
			int rows = em.createNativeQuery("INSERT INTO ACQUISTI (id_pacchetto, id_utente, numero_acquisti) VALUES ("+acq.getPacchetti().getIdPacchetto()+","+acq.getId().getIdUtente()+","
					+acq.getNumeroAcquisti()+ ")").executeUpdate();
			if(rows!=1){
				throw new Exception("HO INSERITO "+rows+" TUPLE ANZICHE' UNA");
			}
		}catch(Exception e){
			throw new Exception("ERRORE INSERIMENTO ACQUISTO NEL DB: ");
		}

		// UPDATE DISPONIBILITA PACCHETTO
		try{
			int rows = em.createQuery("UPDATE Pacchetti p SET p.disponibilita="+(acq.getPacchetti().getDisponibilita()-acq.getNumeroAcquisti())+" "
					+ "WHERE p.idPacchetto="+acq.getPacchetti().getIdPacchetto()).executeUpdate();
			if(rows!=1){
				throw new Exception("ZIO CANE, "+rows+" TUPLE INVECE CHE UNA");
			}
		}catch(Exception e){
			throw new Exception("ERRORE AGGIORNAMENTO DISPONIBILITA: "+e.getMessage());
		}

	}

	/**
	 * Cerca tutti gli acquisti di un {@link User}
	 * 
	 * @param u = l'{@link UtenteDTO} di cui cercare gli acquisti
	 * 
	 * @return tutti gli {@link AcquistoDTO} in un'{@link ArrayList}
	 */
	@Override
	public ArrayList<AcquistoDTO> getAcquistiForUser(UtenteDTO u){
		UtenteEJBImpl uejb = new UtenteEJBImpl(em);
		ArrayList<AcquistoDTO> acquisti = new ArrayList<AcquistoDTO>();
		int iduser = uejb.getIdFromUsername(u.getUsername());
		List<Acquisti> lacq;
		Iterator<Acquisti> iacq;
		Acquisti temp = new Acquisti();
		List<User> lu;

		lu=uejb.getAllUtenti();

		// MOLTI DUBBI
		lacq=em.createQuery("SELECT a FROM Acquisti a WHERE a.id.idUtente= :par").setParameter("par", iduser).getResultList();
		iacq=lacq.iterator();

		while(iacq.hasNext()){
			temp=iacq.next();
			acquisti.add(Entities2DTO.convertAcquisti(temp, temp.getId(), lu));
		}

		return acquisti;
	}


	/**
	 * Metodo che prende una entity {@link Pacchetti} e ritorna il corrispondente DTO ({@link PacchettoDTO})
	 * 
	 * @param p
	 * @return
	 */
	private PacchettoDTO convertPacket(Pacchetti p){

		PacchettoDTO help = new PacchettoDTO();

		/*
		System.out.println("Pacchetto creato: "+p.getIdPacchetto());
		System.out.println(p.getAlloggi().getCitta().getName());
		System.out.println(p.getCategorie().getDescrizione());
		System.out.println(p.getTrasportiSingoli1().getData());
		System.out.println(p.getTrasportiSingoli2().getData());
		System.out.println(p.getSconto());
		System.out.println(p.getTrasportiSingoli1().getPrezzo()+ p.getTrasportiSingoli2().getPrezzo());
		 */
		help.setId(p.getIdPacchetto());
		help.setCitta(Entities2DTO.convertCitta(p.getAlloggi().getCitta()));
		help.setDescrizione_categoria(p.getCategorie().getDescrizione());
		help.setPartenza(p.getTrasportiSingoli1().getData());
		help.setRitorno(p.getTrasportiSingoli2().getData());
		help.setSconto(p.getSconto());
		help.setPrezzo(p.getTrasportiSingoli1().getPrezzo()+ p.getTrasportiSingoli2().getPrezzo());

		return help;
	}


}
